#include <iostream>
#include <algorithm>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <numeric>
#include <functional>

using namespace std;

string DIRNAME("\".\\\"");
string STOREFILE("test.txt");
string FILTER("*.dat");
string INIFILE("gage2scope.ini");
int VT = 0;
int WIDTH = 1;
int PULSE_DELTA = 2;
int DROP_RATIO = 3;
int BELOW_DROP_RATIO = 4;
size_t SIZEOFINIFILE = 5;
vector<double> INIVALUES;
int DROP_RATIO_X_PEAK = 0;

template <class T> bool from_string(T& t, const std::string& s) 
{        
	std::istringstream iss(s);
	return !(iss >> t).fail(); 
} 

int negateInt(int val)
{
	return -val;
}

int smoothData(int &n)
{
	int *i = &n;
	return (i[-3] + 2*i[-2] + 3*i[-1] + 3*i[0] + 3*i[1] + 2*i[2] + i[3]) / 15;
}

int interpretData(int &n)
{
	int *X = &n;
	int tmp = X[2] - X[0];
	if (tmp > 0)
	{
		if (tmp > INIVALUES[VT])
			return 11111; // Peak found
		else
			return 1; //Increasing
	}
	else if (tmp < 0)
		return -1; //Decreasing Value
	else if (tmp == 0)
		return 0; //Flat value
	return -11111; //error
}
int compare(int val)
{
	return (val < DROP_RATIO_X_PEAK);
}

int main()
{
	string sysCall("dir /b ");
	sysCall += DIRNAME;
	sysCall += FILTER;
	sysCall += string(" > ");
	sysCall += STOREFILE;
	system ( sysCall.c_str() );
	//ToDo: Throw an exception if either of the two files don't exist.
	fstream txtFile(STOREFILE.c_str());
	fstream iniFile(INIFILE.c_str());
	vector<string> sv;

	if (!iniFile.good()||!txtFile.good())
	{
		//Exception
	}
	else
	{
		cout << "\nNecessary Files exist and opened sucessfully.";
	}
	for (size_t i = 0; i < SIZEOFINIFILE; i ++)
	{
		string tmp;
		getline(iniFile, tmp);
		double val;
		//ToDo: Throw an exception if you can't convert it.
		from_string<double>(val, tmp.substr(tmp.find_first_of("=",0)+1,tmp.size())); // rip the value from the string
		INIVALUES.push_back(val);
	}
	copy(istream_iterator<string>(txtFile), istream_iterator<string>(), back_inserter(sv));
	for (size_t i = 0; i < sv.size(); i ++)
	{
		fstream datFile(sv[i].c_str());
		cout << "\n\n|----------" << sv[i] << "----------|";
		vector<int> v1;
		vector<int> peakData;
		transform(istream_iterator<int>(datFile), istream_iterator<int>(), back_inserter(v1), negateInt);
		vector<int> sv1(v1);
		transform(v1.begin()+4, v1.end()-4, sv1.begin()+4, smoothData);
		transform(sv1.begin(), sv1.end(), back_inserter(peakData), interpretData);
		int posOfStartOfPeak = 0;
		int posOfPeakOfPeak = 0;
		int areaEndPos = 0;
		bool end = false;
		for (size_t x = 0; x < peakData.size(); x ++)
		{
			if (peakData[x] == 11111) // Start of the peak
			{
				posOfStartOfPeak = x;
				do
				{
					int startOfPiggy = 0; //maybe I don't need this
					x++;
					if (x == peakData.size())
					{
						end = true;
						break;
					}
					//Find the peak of the peak.
					if (posOfPeakOfPeak == 0)
					{
						if (peakData[x] > 0)
						{
							//do nothing we don't care.
						}
						else
						{
							posOfPeakOfPeak = x-1;
						}
					}
					//Check to see if there is a piggybackpeak
					if ((x - posOfStartOfPeak <= INIVALUES[PULSE_DELTA])&&(posOfPeakOfPeak != 0)) // within range of a piggyback
					{
						if ((posOfPeakOfPeak != 0)&&(peakData[x] == 11111)) // Found a potential piggyback
						{
							startOfPiggy = x; // do not include the start of piggy peak
							DROP_RATIO_X_PEAK = sv1[posOfPeakOfPeak]*INIVALUES[DROP_RATIO];
							int result = count_if(sv1.begin() + posOfPeakOfPeak, sv1.begin() + startOfPiggy + 1, compare);
							if (result >= INIVALUES[BELOW_DROP_RATIO])
							{
								posOfStartOfPeak = x;
								posOfPeakOfPeak = 0;
								//set i to the start of the new important pulse and forget about the first pulse.
							}
							else
							{
								cout << "\nStart of Peak: " << posOfStartOfPeak;
								cout << "\nposition of the Peak of the Peak: " << posOfPeakOfPeak;
								cout << "\nArea of Peak: " << accumulate(v1.begin() + posOfStartOfPeak, v1.begin() + x, 0.0f);
								posOfStartOfPeak = x;
								posOfPeakOfPeak = 0;
								//calculate the area up to here move i to the start of the next pulse and start over.
							}
						}
					}
					if (posOfPeakOfPeak != 0)
					{
						if (x - posOfStartOfPeak < INIVALUES[WIDTH])//still inside width
						{
							if ((posOfPeakOfPeak != 0)&&(peakData[x] == 11111))//found a peak before the width ended and it's not a piggyback
							{
								cout << "\nStart of Peak: " << posOfStartOfPeak;
								cout << "\nposition of the Peak of the Peak: " << posOfPeakOfPeak;
								cout << "\nArea of Peak: " << accumulate(v1.begin() + posOfStartOfPeak, v1.begin() + x, 0.0f);
								posOfStartOfPeak = x;
								posOfPeakOfPeak = 0;
								//calculate the area up to here move i to the start of the next pulse and start over.
							}
						}
						else
						{
							cout << "\nStart of Peak: " << posOfStartOfPeak;
							cout << "\nposition of the Peak of the Peak: " << posOfPeakOfPeak;
							cout << "\nArea of Peak: " << accumulate(v1.begin() + posOfStartOfPeak , v1.begin() + posOfStartOfPeak + INIVALUES[WIDTH], 0.0f);
							posOfStartOfPeak = 0;
							posOfPeakOfPeak = 0;
							break;
							//calculate the area up to here and break.
						}
					}
				}while(!end);
			}
		}
	}
	cin.get();
	return 0;
}